// 泛型：指在定义函数、接口或者类的时候不提前指定具体的数据类型 ，当使用时再指定具体的数据类

// 函数使用泛型参数
// 提前设计数据类型，直接规定了数据类型
function foo(x: string, y: string): string {
    return x + y
}

// 数组的数据类型规定
// ['ss','ss']   string[]
// [11,22,55]    number[]


// 没有规定数据类型
function fun<T>(x: T, y: T): T[] {
    return [x, y]
}
// 当调用时，传入数据类型
fun<string>('122', 'hjkl');
console.log(fun<string>('122', 'hjkl'));

fun<number>(11, 55);
console.log(fun<number>(11, 55));

// 返回值为元组tuple
function fofu<T, K>(a: T, b: K): [T, K] {
    return [a, b];
}
fofu<string, number>('11', 111);
fofu<string, boolean>('78', false);

// 接口定义泛型
/* interface Person {
    name: string,
    age: number,
    sex: string
}
let obj: Person = {
    name: 'tom',
    age: 10,
    sex: '男'
}
console.log(obj); */

// 将接口定义为一个泛型的接口

interface Person<T, K> {
    name: T,
    age: K,
    sex: T
}
let obj: Person<string, number> = {
    name: 'jack',
    age: 15,
    sex: '男'
}
console.log(obj);

let obj1: Person<boolean, number> = {
    name: false,
    age: 10,
    sex: true
}
console.log(obj1);

// 泛型类
// 一说到类或者构造函数 脑海必须想到三个地方  自身的方法属性 实例对象上的方法属性  原型对象上的方法属性
/* class Animal {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    // 原型对象上的方法
    jump(str: string): string {
        return this.name + str;
    }
    // 静态方法
    static run(num: number): number {
        return num
    }
} */

// 泛型类
class Animal<T, N>{
    name: T;
    age: N;
    constructor(name: T, age: N) {
        this.name = name;
        this.age = age;
    }
    // 因为咱们定义的泛型，如果做加法或者拼串 
    jump(str: T): T {
        return str;
    }
    // 静态成员不能引用类类型形参
    //静态成员 构造函数自身上的属性和方法 

}
let dahuang = new Animal<string, number>('dahuang', 2);
console.log(dahuang);
let xiaomaomi = new Animal<boolean, 'xx'>(false, 'xx');
console.log(xiaomaomi);

// 类的数据类型使用接口进行定义  泛型接口
interface Base<T, K> {
    data: T[],
    add: (x: T, y: K) => void
}

class User implements Base<string, number>{
    // 在每一个实例对象行都添加了一个data值，
    data: string[] = [];
    // 添加到原型对象上的方法
    add(x: string, y: number): void {
        this.data.push(x);
        // 因为我们规定的data是字符串类型的数组，而是数字
        // this.data.push(y);
        console.log(y);
    }

}

let xiaoming = new User();
console.log(xiaoming);


// 泛型约束
/* function boo<T>(x: T) {
    // 因为T是类型形参  T传入的是什么值一定吗？
    console.log(x.length);//报错
} */

/* function boo1(x: string) {
    console.log(x.length);
}
function boo2(x: number) {
    console.log(x.length);
} */

// 泛型约束

interface Length {
    length: number
}

function boo3<T extends Length>(x: T) {
    console.log(x.length);
}

boo3<string>('aaaa');
// boo3<number>(45631);


// ts基本数据类型
// number string Boolean  字面量 void 数组 对象 元组 never undefined null any unknown  枚举
// 类型联合 

interface Test {
    name: string
}
// never用不存在的

function fooFun(): never {
    while (true) { }
}

export {
    foo
}